package cn.zhangfusheng.elasticsearch.factory.proxy;

import cn.zhangfusheng.elasticsearch.mybatis.ElasticSearchWithMybatisXmlConfig;
import cn.zhangfusheng.elasticsearch.repository.ElasticSearchRepository;
import cn.zhangfusheng.elasticsearch.scan.ElasticSearchEntityRepositoryDetail;
import cn.zhangfusheng.elasticsearch.template.ElasticSearchRestTemplate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * jdk 代理
 * @author fusheng.zhang
 * @date 2022-04-29 17:51:35
 */
public class RepositoryJdkProxy<T extends ElasticSearchRepository<?>> extends RepositoryProxy<T> {

    private final ElasticSearchRepository<?> defaultElasticSearchRepository;
    private final Class<? extends ElasticSearchRepository<?>> objectType;

    public RepositoryJdkProxy(
            ElasticSearchRepository<?> defaultElasticSearchRepository,
            ElasticSearchEntityRepositoryDetail entityRepositoryDetail,
            ElasticSearchRestTemplate elasticSearchRestTemplate,
            ElasticSearchWithMybatisXmlConfig elasticSearchWithMybatisXmlConfig) {
        super(entityRepositoryDetail, elasticSearchRestTemplate, elasticSearchWithMybatisXmlConfig);
        this.objectType = entityRepositoryDetail.getElasticSearchRepositoryClass();
        this.defaultElasticSearchRepository = defaultElasticSearchRepository;
    }

    @SuppressWarnings("unchecked")
    @Override
    public T getObject() {
        return (T) Proxy.newProxyInstance(this.objectType.getClassLoader(), new Class[]{objectType}, getInvocationHandler());
    }

    private InvocationHandler getInvocationHandler() {
        return (proxy, method, args) -> {
            if (method.getDeclaringClass() == Object.class) return method.invoke(this, args);
            if (super.isDefaultMethod(method)) return method.invoke(defaultElasticSearchRepository, args);
            return getResult(method, args);
        };
    }
}
